home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / master / Examples / Visual / VMake / state.c < prev    next >
C/C++ Source or Header  |  1994-02-01  |  29KB  |  923 lines

  1. #include "vmake.h"
  2.  
  3. struct Gadget *oldgad;
  4.  
  5. Prototype void handle_hit(struct Gadget *gad,int shift, int doubleclick);
  6. Prototype void set_cyc_state(struct G_CYCLE *cyc,struct G_VALUE *val);
  7. Prototype void handle_list(struct G_LIST *list,struct Gadget *gad,int class,char *buf, int doubleclick);
  8. Prototype void redraw_gadget(struct Gadget *gad);
  9. Prototype void recalc_prop(struct G_LIST *list,UWORD *body,UWORD *sltop);
  10. Prototype int  newpos(struct G_LIST *list,int spos,struct G_ENTRY *ent);
  11. Prototype void set_gadlist(struct GADLIST *gadlist,int state);
  12. Prototype void set_gadgets(int state);
  13. Prototype int  get_work_filename(char *gfname, int spat);
  14. Prototype void mark_clean(void);
  15. Prototype int  test_dirty(void);
  16.  
  17. /***********************************************************************************
  18.  * Procedure: handle_hit
  19.  * Synopsis:  handle_hit(gadget, shift, doubleclick);
  20.  * Purpose:   Handle the processing for the hit on a gadget.
  21.  ***********************************************************************************/
  22. void handle_hit(struct Gadget *gad,
  23.                 int    shift,
  24.                 int    doubleclick
  25.                )
  26. {
  27.    struct G_OBJECT *obj;
  28.  
  29.    obj = (struct G_OBJECT *)gad->UserData;
  30.    /* Ignore any hits on disabled gadgets */
  31.    if ((gad->Flags & GADGHIGHBITS) == GADGHNONE) return;
  32.  
  33.    if (doubleclick)
  34.    {
  35.       if (oldgad != gad)
  36.          doubleclick = 0;
  37.    }
  38.    else
  39.       oldgad = gad;
  40.  
  41. #ifdef DBG_JGM
  42. printf("Double click state = %d\n", doubleclick);
  43. #endif
  44.  
  45.    switch(obj->class)
  46.    {
  47.       case CLASS_STRING:
  48.          break;
  49.       case CLASS_CYCLE:
  50.          {
  51.             /* We need to advance the string to the next state */
  52.             /* When we refresh the gadget, we need to first blank it out */
  53.             struct G_CYCLE *cyc;
  54.             struct G_VALUE *val;
  55.  
  56.             cyc = (struct G_CYCLE *)obj;
  57.             val = cyc->curval;
  58.  
  59.             if (shift)
  60.             {
  61.                for(val = cyc->values;
  62.                    (val->next != NULL) && (val->next != cyc->curval);
  63.                    val = val->next);
  64.             }
  65.             else
  66.             {
  67.                val = val->next;
  68.                if (val == NULL) val = cyc->values;
  69.             }
  70.             set_cyc_state(cyc, val);
  71.             obj->state |= DIRTY_BIT;
  72.          }
  73.          break;
  74.       case CLASS_CHECK:
  75.          obj->state = ((gad->Flags & SELECTED) != 0) & DIRTY_BIT;
  76.          break;
  77.       case CLASS_LIST:
  78.          handle_list((struct G_LIST *)obj, gad, gad->GadgetID, NULL, doubleclick);
  79.          break;
  80.       case CLASS_BUTTON:
  81.          if (!doubleclick) /* don't edit or compile twice for a double click */
  82.             do_command(global.button[obj->state & STATE_MASK].command);
  83.          break;
  84.       default:
  85.          break;
  86.    }
  87. }
  88. /***********************************************************************************
  89.  * Procedure: redraw_gadget
  90.  * Synopsis:  redraw_gadget(gadget);
  91.  * Purpose:   Rerender a gadget on the screen
  92.  ***********************************************************************************/
  93. void redraw_gadget(struct Gadget *gad
  94.                   )
  95. {
  96.    SetBPen(global.rp, 0);
  97.    SetAPen(global.rp, 0);
  98.    RectFill( global.rp, gad->LeftEdge + VBAR, gad->TopEdge + HBAR,
  99.                          gad->LeftEdge + gad->Width - 1 - VBAR,
  100.                          gad->TopEdge + gad->Height - 1 - HBAR);
  101.    RefreshGList( gad, global.window, NULL, 1);
  102. }
  103.  
  104. /***********************************************************************************
  105.  * Procedure: set_cyc_state
  106.  * Synopsis:  set_cyc_state(cyc,val)
  107.  * Purpose:   Set a cycle gadget to a give value
  108.  ***********************************************************************************/
  109. void set_cyc_state(struct G_CYCLE *cyc,
  110.                    struct G_VALUE *val
  111.                   )
  112. {
  113.    struct G_STRING *str;
  114.    struct Gadget *gad;
  115.  
  116.    /* See It is currently being displayed on the screen.  If so, we will have to */
  117.    /* do some cleanup work to get it updated.                                    */
  118.    str = cyc->curval->string;
  119.    if ((str != NULL) && (str->base.gadget != NULL))
  120.    {
  121.       /* If there is a string gadget currently in the cycle gadget, we need */
  122.       /* to free it up                                                      */
  123.       RemoveGList( global.window, str->base.gadget, 1);
  124.       free_gadget(str->base.gadget);
  125.    }
  126.  
  127.    if (val == NULL) return;
  128.  
  129.    cyc->curval = val;
  130.  
  131.    /* Now, if we are currently displaying the gadget, we need to get it on the */
  132.    /* screen.                                                                  */
  133.    if (gad = cyc->base.gadget)
  134.    {
  135.       struct IntuiText *itext;
  136.       struct Gadget *strgad;
  137.       int oldpos;
  138.  
  139.       itext = gad->GadgetText->NextText;
  140.       itext->IText = val->title;
  141.  
  142.       strgad = setup_cycle_gadget(gad, itext, val);
  143.  
  144.       oldpos = RemoveGList(global.window, gad, 1);
  145.       AddGList(global.window, gad, oldpos, 1, NULL);
  146.  
  147.       if (strgad) AddGadget( global.window, strgad, 0);
  148.  
  149.       /* Wipe out the inner area of the gadget so that we can redraw it later */
  150.       redraw_gadget(gad);
  151.       if (strgad) redraw_gadget(strgad);
  152.    }
  153. }
  154.  
  155. /***********************************************************************************
  156.  * Procedure: handle_list
  157.  * Synopsis:  handle_list(list, gadget, int class, buf, doubleclick);
  158.  * Purpose:   Handle the processing for the hit on a list gadget.
  159.  ***********************************************************************************/
  160. void handle_list(struct G_LIST *list,
  161.                  struct Gadget *gad,
  162.                  int class,
  163.                  char *buf,
  164.                  int doubleclick
  165.                 )
  166. {
  167.    struct G_ENTRY *ent, *prevent;
  168.    struct PropInfo *pi;
  169.    int expect;
  170.    int docmnd;
  171.    int pos;
  172.    int prevpos;
  173.    int i;
  174.    int oldpos[MAX_LIST];
  175.  
  176.    static int oldpropidx;
  177.  
  178.    expect = docmnd = 0;
  179.    pos = -1; /* used to indicate no valid selection */
  180.    if (list->sel) /* we should expect a valid selection */
  181.    {
  182.       expect = 1;
  183.       pos = list->base.state & STATE_MASK;
  184.    }
  185.    prevpos = pos;
  186.  
  187.    switch(class & CLASS_MASK) /* Isolate class from subclass */
  188.    {
  189.       case CLASS_ADD:
  190.       {
  191.          int nameinbuf = 0;
  192.          /* Note that gad parameter may not be set on entry. In this case */
  193.          /* if buf parm is set, it has name of file to add, otherwise     */
  194.          /* request a name.  No way to enter a name for Dos 1.3 yet.      */
  195.          if (doubleclick) /* Don't put up requester twice */
  196.             return;
  197.          ent = get_mem(sizeof(struct G_ENTRY));
  198.          if (ent == NULL) 
  199.          {
  200.             request(1, TEXT_NOMEM, NULL, NULL);
  201.             return;
  202.          }
  203.  
  204.          if (buf)
  205.             if (*buf != '\0')
  206.             {
  207.                strcpy(ent->buf, buf);
  208.                nameinbuf = 1;
  209.             }
  210.          if (!nameinbuf)
  211.          {
  212.             if (get_work_filename(ent->buf, CONFIG_FILES) == 0)
  213.             {
  214.                /* User aborted file request, we need to give up too */
  215.                free_mem(ent, sizeof(struct G_ENTRY));
  216.                global.rexxrc = TEXT_CANCEL; /* It's what happened...   */
  217.                return; /* don't mess around with gadgets */
  218.             }
  219.          }
  220.  
  221.          /* we're committed - make sure we select it, whereever we put it */
  222.          expect = 1;
  223.          /* now link the new name into the list */
  224.          if (list->first == NULL)
  225.          {
  226.             int oldpos;
  227.             oldpos = RemoveGList(global.window, list->delgad, 1);
  228.             list->delgad->Flags   &= ~GADGDISABLED;
  229.             AddGList(global.window, list->delgad, oldpos, 1, NULL);
  230.             redraw_gadget(list->delgad);
  231.             list->top = list->first = ent;
  232.             pos = 0; /* select the entry we just added */
  233.          }
  234.          else
  235.          {
  236.             if (pos == -1)  /* if nothing selected, add at top of */
  237.                pos = 0;     /* display - and select it            */
  238.             prevent = list->top;
  239.             for (i = 0; (i < pos) && (prevent != NULL); i++)
  240.                prevent = (struct G_ENTRY *)prevent->base.next;
  241.             /* Insert in front of prevent */
  242.             ent->base.next = (struct G_OBJECT *)prevent;
  243.             if (prevent)
  244.             {
  245.                ent->base.prev = prevent->base.prev;
  246.                prevent->base.prev = (struct G_OBJECT *)ent;
  247.             }
  248.             if (ent->base.prev)
  249.             {
  250.                if (list->top == prevent) list->top = ent;
  251.                ent->base.prev->next = (struct G_OBJECT *)ent;
  252.             }
  253.             else
  254.             {
  255.                list->top = list->first = ent;
  256.             }
  257.             expect = 1;
  258.          }
  259.          /* the list has been changed */
  260.          list->base.state |= DIRTY_BIT;
  261.          break;
  262.       }
  263.       case CLASS_DEL:
  264.          if (doubleclick) /* don't delete two objects by mistake... */
  265.             return;
  266.          if (pos == -1)   /* nothing selected - don't pick one at random...*/
  267.             return;
  268.          ent = list->top;
  269.          for (i = 0; (i < pos) && (ent != NULL); i++)
  270.             ent = (struct G_ENTRY *)ent->base.next;
  271.          /* We want to delete ent */
  272.          if (ent == NULL) return;
  273.          if (ent->base.next)
  274.             ent->base.next->prev = ent->base.prev;
  275.          if (ent->base.prev)
  276.             ent->base.prev->next = ent->base.next;
  277.          else
  278.             list->first = (struct G_ENTRY *)ent->base.next;
  279.  
  280.          /* Update the base pointer so that we are looking at the right space */
  281.          if (list->top == ent)
  282.          {
  283.             list->top = (struct G_ENTRY *)ent->base.next;
  284.             if (list->top == NULL)
  285.                list->top = (struct G_ENTRY *)ent->base.prev;
  286.          }
  287.          free_mem(ent, sizeof(struct G_ENTRY));
  288.          /* the list has been changed */
  289.          list->base.state |= DIRTY_BIT;
  290.          /* and note that we fall through to set state of del gadget */
  291.          goto dodelgad;
  292.          /* except that we want to leave the next item selected - it */
  293.          /* will have moved up to the display position just vacated. */ 
  294.       case CLASS_REFRESH:
  295.          expect = 0;
  296.  
  297. dodelgad:
  298.          {
  299.             int oldpos;
  300.  
  301.             oldpos = RemoveGList(global.window, list->delgad, 1);
  302.             if (list->first == NULL)
  303.                list->delgad->Flags   |=  GADGDISABLED;
  304.             else
  305.                list->delgad->Flags   &= ~GADGDISABLED;
  306.             AddGList(global.window, list->delgad, oldpos, 1, NULL);
  307.             redraw_gadget(list->delgad);
  308.          }
  309.          RefreshGList( list->delgad, global.window, NULL, 5);
  310.          break;
  311.       case CLASS_UP:
  312.          expect = 0; /* trying to move deselects */
  313.          if ((list->top != NULL) && (list->top->base.prev != NULL))
  314.          {
  315.             list->top = (struct G_ENTRY *)list->top->base.prev;
  316.          }
  317.          break;
  318.       case CLASS_DOWN:
  319.          {
  320.             struct G_ENTRY *ent;
  321.             expect = 0; /* trying to move deselects */
  322.             if ((list->top != NULL) && (list->top->base.next != NULL))
  323.             {
  324.                list->top = (struct G_ENTRY *)list->top->base.next;
  325.             }
  326.             ent = list->first;
  327.             i = list->maxent - global.listsize;
  328.             while (ent && i)
  329.             {
  330.                if ((ent = (struct G_ENTRY *)ent->base.next) == list->top) 
  331.                   break;
  332.                i--;
  333.             }
  334.             if ((i == 0) && (ent != NULL))
  335.                list->top = ent;
  336.          }
  337.          break;
  338.       case CLASS_PROP:
  339.          {
  340.             int maxtop;
  341.             expect = 0; /* trying to move deselects */
  342.             pi = (struct PropInfo *)gad->SpecialInfo;
  343.             maxtop = list->maxent - global.listsize;
  344.             i = (pi->VertPot*(2*maxtop))/MAXBODY;
  345.             i = (i + 1)/ 2; /* rounding for more natural button behavior */
  346.             if (i > maxtop) i = maxtop;
  347.             if ((global.mouseprop) && (i == oldpropidx))
  348.             {
  349.                /* don't want to refresh the list unless the view has     */
  350.                /* changed.  Have to refresh the prop gadget or it decays */
  351.                /* all over the border.                                   */
  352.                UWORD body, sltop;
  353.                recalc_prop(list, &body, &sltop);
  354.                NewModifyProp(list->slider, global.window, NULL,
  355.                              AUTOKNOB | FREEVERT | PROPBORDERLESS,
  356.                              0, sltop, MAXBODY, body, 1L);
  357.                return;
  358.             }
  359.             else
  360.                oldpropidx = i;   
  361.             list->top = list->first;
  362.             while((i > 0) && (list->top != NULL))
  363.             {
  364.                list->top = (struct G_ENTRY *)list->top->base.next;
  365.                i--;
  366.             }
  367.             if (list->top == NULL) list->top = list->first;
  368.          }
  369.          break;
  370.       case CLASS_LIST:
  371.          pos = class >> SUBCLASS_OFF;
  372.          expect = 1;
  373.          if (doubleclick)
  374.             docmnd = 1; /* user double clicked on a list entry         */
  375.          break;
  376.       case CLASS_SELECT:
  377.          {
  378.             int spos;
  379.             int simplename;
  380.             struct G_ENTRY *ent;
  381.  
  382.             expect = 0; /* signal nothing to select                    */
  383.             pos = -1; /* nothing selected                              */
  384.             if (buf == NULL) /* no parameter - nothing to do           */
  385.                break;
  386.             if (*buf == '\0') /* empty string not a valid list entry   */
  387.                break;
  388.             /* set pathname true if path separators present, false (or */
  389.             /* NULL) otherwise                                         */
  390.             simplename = (strpbrk(buf, ":/") == NULL);
  391.             ent = list->first;
  392.             spos = 0;
  393.             while (ent)
  394.             {
  395.                char *fnp, *tp;
  396.                fnp = ent->buf;
  397.                if (simplename)
  398.                /* want to match simple name - ignore any path in list entry */
  399.                {
  400.                   tp = strrchr(ent->buf, '/');
  401.                   if (tp == NULL) /* no slash, try for a colon         */
  402.                      tp = strrchr(ent->buf, ':');
  403.                   if (tp != NULL) /* strip off the whole path          */
  404.                      fnp = tp + 1;
  405.                }
  406.                if (stricmp(fnp, buf))
  407.                {
  408.                   /* does not match, step through list                 */
  409.                   ent = (struct G_ENTRY *)ent->base.next;
  410.                   spos++;
  411.                }
  412.                else
  413.                   break;
  414.             }
  415.             if (ent == NULL) /* didn't find a match in the list        */
  416.                break;
  417.             /* we're selected something, now figure out where it goes  */
  418.             expect = 1;
  419.             pos = newpos(list, spos, ent);
  420.          }
  421.          break;
  422.       case CLASS_LTOP:
  423.       case CLASS_LBOT:
  424.          int spos;
  425.          struct G_ENTRY *ent;
  426.  
  427.          ent = list->first; /* tricky: not needed when going to bottom */
  428.          if ((class & CLASS_MASK) == CLASS_LTOP)
  429.             spos = 0;
  430.          else
  431.             spos = list->maxent-1;
  432.          expect = 1;
  433.          pos = newpos(list, spos, ent);
  434.          break;
  435.       case CLASS_LUP:
  436.       case CLASS_LDN:
  437.          int spos;
  438.          struct G_ENTRY *ent, *sent;
  439.  
  440.          sent = list->sel;
  441.          if ((class & CLASS_MASK) == CLASS_LUP)
  442.             sent = (struct G_ENTRY *)sent->base.prev;
  443.          else
  444.             sent = (struct G_ENTRY *)sent->base.next;
  445.          spos = 0;
  446.          ent = list->first;
  447.          while (ent)
  448.          {
  449.             if (ent == sent)
  450.                break;
  451.             ent = (struct G_ENTRY *)ent->base.next;
  452.             spos++;
  453.          }
  454.          expect = 1;
  455.          pos = newpos(list, spos, ent);
  456.          break;
  457.       default:
  458.          printf("Unexpected list gadget class 0x%x\n", class);
  459.          break;
  460.    }
  461.  
  462.    list->sel = NULL;  /* turn off selection & see if we reselect */
  463.  
  464.    gad = list->base.gadget;
  465.  
  466.    if (expect)
  467.    {
  468.       /* Make sure that we are actually in a position to enable the */
  469.       /* requested string gadget.  If not, just ignore the request  */
  470.       /* Start from the top of the display and see if there's an    */
  471.       /* entry at the requested position.                           */
  472.       ent = list->top;
  473.       for(i = pos; ent && (i > 0); i--)
  474.          ent = (struct G_ENTRY *)ent->base.next;
  475.  
  476.       if (ent)
  477.       {
  478.          list->sel = ent;
  479.          }
  480.       else
  481.       {
  482.          pos = -1;
  483.          /* clear out the selected string gadget */
  484.          list->base.state = list->base.state & DIRTY_BIT;
  485.       }
  486.    }
  487.    else
  488.    {
  489.       pos = -1;
  490.    }
  491.    /* point to selected entry gadget if any */
  492.    list->base.state = (list->base.state & DIRTY_BIT) + (pos & STATE_MASK);
  493.  
  494.    /* handle refreshing of LIST hit differently to reduce screen flash   */
  495.    /* and improve response to double click (remove gadget for less time) */
  496.    if ((class & CLASS_MASK) != CLASS_LIST)
  497.    {
  498.       for(i = global.listsize-1; i >= 0; i--)
  499.       {
  500.          oldpos[i] = RemoveGList(global.window, list->btngad[i], 2);
  501.       }
  502.       reset_list_object(list, pos);
  503.  
  504.       /* Wipe out the inner area of the gadget so that we can redraw it later */
  505.       redraw_gadget(gad);
  506.  
  507.       for(i = 0; i < global.listsize; i++)
  508.       {
  509.          AddGList(global.window, list->btngad[i], oldpos[i], 2, NULL);
  510.          RefreshGList( list->btngad[i], global.window, NULL, 2);
  511.       }
  512.    }
  513.    else
  514.    {
  515.       if ((prevpos != -1) && (prevpos != pos))
  516.       /* redraw old button gadget to wipe out the border */
  517.       {
  518.          int oldpos;
  519.          struct Gadget *bgad = list->btngad[prevpos];
  520.          oldpos = RemoveGList(global.window, list->btngad[prevpos], 2);
  521.          list->strgad[prevpos]->GadgetRender = NULL;
  522.          /* standard redraw() misses the edges of the border *sigh*       */
  523.          /* this sizing is a bit slimy and ad hoc but it seems to work... */
  524.          SetBPen(global.rp, 0);
  525.          SetAPen(global.rp, 0);
  526.          RectFill( global.rp, bgad->LeftEdge, bgad->TopEdge + 1,
  527.                    bgad->LeftEdge + bgad->Width - 1,
  528.                    bgad->TopEdge + bgad->Height - 2 + global.listextra);
  529.          AddGList(global.window, list->btngad[prevpos], oldpos, 2, NULL);
  530.          RefreshGList( list->btngad[prevpos], global.window, NULL, 2);     
  531.       }
  532.       if (pos != -1)
  533.       /* draw border for newly selected list gadget */
  534.       {
  535.          int oldpos;
  536.          oldpos = RemoveGList(global.window, list->btngad[pos], 2);
  537.          list->strgad[pos]->GadgetRender = list->sborder;
  538.          AddGList(global.window, list->btngad[pos], oldpos, 2, NULL);
  539.          RefreshGList( list->btngad[pos], global.window, NULL, 2);
  540.       }
  541.    }
  542.  
  543. /* remove to prevent typing into gadget
  544.    if (pos >= 0)
  545.       ActivateGadget(list->strgad[pos], global.window, NULL);
  546. */
  547.  
  548.    {
  549.       UWORD body, sltop;
  550.       recalc_prop(list, &body, &sltop);
  551.       NewModifyProp(list->slider, global.window, NULL,
  552.                     AUTOKNOB | FREEVERT | PROPBORDERLESS,
  553.                     0, sltop, MAXBODY, body, 1L);
  554.    }
  555.  
  556.    if (docmnd && list->sel) /* double clicked on a valid entry */
  557.       do_command(global.text[CONFIG_DCLICK]);
  558. }
  559. /***********************************************************************************
  560.  * Procedure: recalc_prop
  561.  * Synopsis:  recalc_prop(list)
  562.  * Purpose:   Calculate the appropriate BODY and TOP values for a List Prop gadget
  563.  ***********************************************************************************/
  564. void recalc_prop(struct G_LIST *list,
  565.                  UWORD *body, UWORD *sltop
  566.                )
  567. {
  568.    int count, top, maxtop;
  569.    struct G_ENTRY *ent;
  570.  
  571.    count = top = 0;
  572.    ent = list->first;
  573.  
  574.    while(ent != NULL)
  575.    {
  576.       if (ent == list->top) top = count;
  577.       count++;
  578.       ent = (struct G_ENTRY *)ent->base.next;
  579.    }
  580.  
  581.    list->maxent = count;
  582.  
  583.    *body  = MAXBODY;
  584.  
  585.    *sltop = 0;
  586.    if (count > global.listsize)
  587.    {
  588.       *body  = (MAXBODY * global.listsize) / count;
  589.       maxtop = count - global.listsize;
  590.       if (top > maxtop) top = maxtop;
  591.       *sltop = (MAXBODY * top) / maxtop;
  592.    }
  593.  
  594. }
  595. /***********************************************************************************
  596.  * Procedure: newpos
  597.  * Synopsis:  newpos(list, spos, ent)
  598.  * Purpose:   set display position for a new list selection
  599.  *            caller knows both entry & index - why recalculate?
  600.  ***********************************************************************************/
  601. int  newpos(struct G_LIST *list,int spos,struct G_ENTRY *ent)
  602. {
  603.    int j, pos, dtop, maxtop;
  604.    struct G_ENTRY *dent;
  605.  
  606.    maxtop = list->maxent - global.listsize;
  607.  
  608.    /* Now find the index of the top of the visible display      */
  609.    dent = list->first;
  610.    dtop = 0;
  611.    while (dent)
  612.    {
  613.       if (dent == list->top)
  614.       /* We've reached the start of the visible display         */
  615.          break;
  616.       else
  617.       /* keep counting                                          */
  618.       {
  619.          dent = (struct G_ENTRY *)dent->base.next;
  620.          dtop++;
  621.       }
  622.    }
  623.    if ((spos >= dtop) && ((spos - dtop) < global.listsize))
  624.    /* selection is within range of display                      */
  625.    {
  626.       pos = spos - dtop;
  627.    }
  628.    else if (spos <= maxtop)
  629.    /* can move display to start with selected item              */
  630.    {
  631.       list->top = ent;
  632.       pos = 0;
  633.    }
  634.    else
  635.    /* find the lowest possible entry for the top of the display */
  636.    {
  637.       for (j = dtop; j < maxtop; j++)
  638.          list->top = (struct G_ENTRY *)list->top->base.next;
  639.       pos = spos - maxtop;
  640.    }
  641.  
  642.    return pos;            
  643. }
  644. /***********************************************************************************
  645.  * Procedure: set_gadlist
  646.  * Synopsis:  set_gadlist(gadlist,on/off)
  647.  * Purpose:   Enable or Disable all the gadgets in a list
  648.  ***********************************************************************************/
  649. void set_gadlist(struct GADLIST *gadlist,
  650.                  int state
  651.                 )
  652. {
  653.    struct Gadget *gad;
  654.    struct G_CYCLE *cyc;
  655.    int count;
  656.  
  657.    if ((global.window == NULL) ||
  658.        (gadlist == NULL))
  659.       return;
  660.  
  661.    if (state)
  662.    {
  663.       AddGList( global.window, gadlist->gadgets, 30000, gadlist->count, NULL);
  664.    }
  665.    else
  666.    {
  667.       RemoveGList(global.window, gadlist->gadgets, gadlist->count);
  668.    }
  669.  
  670.    for(gad = gadlist->gadgets, count=gadlist->count;
  671.        gad && count;
  672.        gad = gad->NextGadget, count--)
  673.    {
  674.       cyc = (struct G_CYCLE *)gad->UserData;
  675.  
  676.       if ((cyc->base.class & CLASS_MASK) == CLASS_CYCLE)
  677.       {
  678.          set_cyc_state(cyc, state ? cyc->curval : NULL);
  679.       }
  680.       else if (state)
  681.       {
  682.          if ((cyc->base.class & CLASS_MASK) == CLASS_LIST)
  683.          {
  684.             if (gad == cyc->base.gadget)
  685.                handle_list((struct G_LIST *)cyc, NULL, CLASS_REFRESH, NULL, 0);
  686.          }
  687.          else
  688.          {
  689.              RefreshGList(gad, global.window, NULL, 1);
  690.          }
  691.       }
  692.    }
  693. }
  694.  
  695. /***********************************************************************************
  696.  * Procedure: set_gadgets
  697.  * Synopsis:  set_gadgets(on/off)
  698.  * Purpose:   Enable or Disable all gadgets
  699.  ***********************************************************************************/
  700. void set_gadgets(int state)
  701. {
  702.    static int gadliststate;
  703.  
  704.    if (state == gadliststate)
  705.       /* adding or removing twice in a row causes problems */
  706.       return;
  707.    else
  708.    {
  709.       gadliststate = state;
  710.       set_gadlist(global.gadlist,    state);
  711.    }
  712. }
  713.  
  714. /***********************************************************************************
  715.  * Procedure: get_work_filename
  716.  * Synopsis:  type = get_work_filename(gfname, spat)
  717.  * Purpose:   Parse out a file descriptor and return a type for that name
  718.  *            gfname points to a buffer to receive the name.
  719.  *            spat is the index of a search pattern entry in global.text[]
  720.  ***********************************************************************************/
  721. int get_work_filename(char *gfname, int spat)
  722. {
  723.    char *p;
  724.    int len;
  725.    int n;
  726.  
  727.    if (global.inrexx)
  728.    {
  729.       /* whoever called us should have had a filename parameter */
  730.       global.rexxrc = TEXT_BADPARM;
  731.       return 0;
  732.    }
  733.  
  734.    if (global.freq == NULL) return(0);
  735.  
  736.    set_workdir();
  737.    set_busy();
  738.  
  739.    if (AslBase != NULL)
  740.    {
  741.       struct TagItem taglist[9];
  742.  
  743.       n = 0;
  744.  
  745.       taglist[n  ].ti_Tag  = ASL_Pattern;
  746.       taglist[n++].ti_Data = (ULONG)global.text[spat];
  747.  
  748.       taglist[n  ].ti_Tag  = ASL_File;
  749.       taglist[n++].ti_Data = (ULONG)"";
  750.  
  751.       taglist[n  ].ti_Tag  = ASL_Dir;
  752.       taglist[n++].ti_Data = (ULONG)"";
  753.  
  754.       taglist[n  ].ti_Tag  = ASL_Window;
  755.       taglist[n++].ti_Data = (ULONG)global.window;
  756.  
  757. #ifdef ASLFR_DoSaveMode
  758.       taglist[n  ].ti_Tag  = ASLFR_DoSaveMode;
  759.       taglist[n++].ti_Data = FALSE;
  760. #endif
  761.  
  762. #ifdef ASLFR_DoPatterns
  763.       taglist[n  ].ti_Tag  = ASLFR_DoPatterns;
  764.       taglist[n++].ti_Data = TRUE;
  765. #endif
  766.  
  767. #ifdef ASLFR_RejectIcons
  768.       taglist[n  ].ti_Tag  = ASLFR_RejectIcons;
  769.       taglist[n++].ti_Data = TRUE;
  770. #endif
  771.  
  772. #ifdef ASLFR_SleepWindow
  773.       taglist[n  ].ti_Tag  = ASLFR_SleepWindow;
  774.       taglist[n++].ti_Data = TRUE;
  775. #endif
  776.  
  777.       taglist[n  ].ti_Tag  = TAG_DONE;
  778.       taglist[n++].ti_Data = 0;
  779.  
  780.       if (!AslRequest( (APTR)global.freq, taglist))
  781.       {
  782.          set_idle();
  783.          return(0);
  784.       }
  785.    }
  786.    else
  787.    {
  788.        /* We must have arp.library (otherwise we wouldn't have a file     */
  789.        /* Requester structure.)                                           */
  790.        global.freq->rf_Dir[0] = 0;
  791.        global.freq->rf_File[0] = 0;
  792.        if (!ArpFileRequest( global.freq ))
  793.        {
  794.           set_idle();
  795.           return(0);
  796.        }
  797.    }
  798.    set_idle();
  799.  
  800.    n = strlen(global.freq->rf_Dir);
  801.    if (n > 255) n = 255;
  802.    p = gfname;
  803.    memcpy(p, global.freq->rf_Dir, n);
  804.    p += n;
  805.  
  806.    if ((n > 0) && (p[-1] != ':'))
  807.    {
  808.       *p++ = '/';
  809.       n++;
  810.    }
  811.    len = strlen(global.freq->rf_File);
  812.    if (len == 0) return 0; /* null name string equivalent to cancelling */
  813.    if ((n + len) > 255) len = 255-n;
  814.    strncpy(p, global.freq->rf_File, len);
  815.    p[len] = 0;
  816.  
  817.    if (!stricmp(gfname, "ENV"))
  818.       return(FILE_ENV);
  819.  
  820.    len = strlen(gfname);
  821.    p = gfname + strlen(gfname);
  822.  
  823.    if (len < 2)
  824.       return(FILE_OPTIONS);
  825.  
  826.    if ((len >= 7) && (!stricmp(p-7, "DCCOPTS")))
  827.       return(FILE_OPTIONS);
  828.  
  829.    if ((len >= 9) && (!stricmp(p-9, "DMAKEFILE")))
  830.       return(FILE_DMAKEFILE);
  831.  
  832.    if (!stricmp(p-2, ".H"))
  833.       return(FILE_C);
  834.  
  835.    if (!stricmp(p-2, ".C"))
  836.       return(FILE_C);
  837.  
  838.    return(FILE_OPTIONS);
  839. }
  840.  
  841.  
  842. /***********************************************************************************
  843.  * Procedure: mark_clean
  844.  * Synopsis:  mark_clean()
  845.  * Purpose:   reset DIRTY bit for all string objects
  846.  ***********************************************************************************/
  847. void mark_clean(void)
  848. {
  849.    struct G_OBJECT *obj;
  850.    struct G_STRING *strobj;
  851.    #define cycobj ((struct G_CYCLE *)obj)
  852.  
  853.    obj = global.objects;
  854.    while (obj)
  855.    {
  856.       obj->state &= STATE_MASK; /* reset dirt bit for this object */
  857.       if (obj->class == CLASS_STRING)
  858.          strobj = (struct G_STRING *)obj;
  859.       else
  860.       /* see if it's a cycle which might have a string sub-object */
  861.       {
  862.          if (obj->class == CLASS_CYCLE)
  863.             /* strobj may end up NULL.  That's fine               */
  864.             strobj = cycobj->curval->string;
  865.          else
  866.             strobj = NULL;
  867.       }
  868.       if (strobj)
  869.       {
  870.          /* checkpoint present string - safely                    */
  871.      strncpy(strobj->clean_buf, strobj->buf, MAX_STRING);
  872.       }
  873.       obj = obj->next;
  874.    }
  875.    global.dirtysym = 0; /* flags externally defined symbols       */
  876.    #define cycobj
  877. }
  878. /***********************************************************************************
  879.  * Procedure: test_dirty()
  880.  * Synopsis:  bool = test_dirty()
  881.  * Purpose:   set dirty bits for string objects and return true if any dirty
  882.  *            objects are found
  883.  ***********************************************************************************/
  884. int test_dirty(void)
  885. {
  886.    struct G_OBJECT *obj;
  887.    struct G_STRING *strobj;
  888.    int dirty = 0;
  889.  
  890.    obj = global.objects;
  891.    while (obj)
  892.    /* we want to look at everything, not exit on the first dirty object    */
  893.    /* because this routine also flags any dirty string (sub)objects        */
  894.    {
  895.       if (obj->class == CLASS_STRING)
  896.          strobj = (struct G_STRING *)obj;
  897.       else
  898.       {
  899.          /* if it's a cycle, and we haven't changed the pointer, and this  */
  900.          /* entry in the cycle has a string gadget, see if the string has  */
  901.          /* changed.                                                       */
  902.          if ((obj->class == CLASS_CYCLE) && !(obj->state & DIRTY_BIT))
  903.             strobj = ((struct G_CYCLE *)obj)->curval->string;
  904.          else
  905.             strobj = NULL;
  906.       }
  907.       if (strobj)
  908.          if (strcmp(strobj->buf, strobj->clean_buf) != 0)
  909.             /* not the same as the snapshot last time mark_clean() went by */
  910.             obj->state |= DIRTY_BIT; /* easy for anyone else to see now    */
  911.  
  912.       /* whether string object or not, see if it's dirty */
  913.       if (obj->state & DIRTY_BIT)
  914.          dirty = DOSTRUE;
  915.       obj = obj->next;
  916.    }
  917.  
  918.    if (global.dirtysym) /* has user set any private symbols?               */
  919.       dirty = DOSTRUE;
  920.  
  921.    return dirty;
  922. }
  923.